//
// @Auther: by wujehy 
// @Email:wujehy@qq.com
// @Data:20-4-14
// @Time:上午11:09
//

#include "IoTBusiness.h"
#include "DataBase/DataBaseHelper.h"
#include "GeeJoan/NetWorkPackage.pb.h"
#include "GeeJoan/IoTModule.pb.h"
#include "internaltypes.h"
#include "ServerContext.h"
#include "CacheManager.h"
#include "Tools/CommonTool.h"
#include <sstream>
#include <Tools/GeeJoanMD5.h>

using namespace GeeJoan::Protocol;

std::string genTaskCode()
{
    std::stringstream ss;

    ss << "taskid" << util::timeMicro();
    return ss.str();

}

static std::string genNewDeviceToken(uint64_t Gid, uint64_t did)
{
    // TODO  Token 生成规则
    std::stringstream ss;
    ss << "testToken." << Gid << "." << did << "." << util::timeMicro();
    return ss.str();
}
//
//IoTBusiness::IoTBusiness(
//        int type_sub, int taskid, const TcpConnPtr &con, uint8_t *protoData, int datalen, void *userdata)
//{
//    currSubType = type_sub;
//    currMod = NetWork::NetWorkPackageModel::IOTMod;
//    currTaskid = taskid;
//
//    switch (type_sub)
//    {
//        case IOT_UPLOAD_SENSOR_DATA: // UploadSensor
//        {
//            this->UploadSensor( con, protoData, datalen, userdata );
//            break;
//        }
//        case IOT_FIND_SENSOR_DATA: // FindSensor
//        {
//            this->FindSensor( con, protoData, datalen, userdata );
//            break;
//        }
//        case IOT_CONTROL_DEVICE: // ControlDevice
//        {
//            this->ControlDevice( con, protoData, datalen, userdata );
//            break;
//        }
//        case IOT_CONTROL_ACK://ControlDeviceListerner
//        {
//            this->ControlDeviceAck( con, protoData, datalen, userdata );
//            break;
//        }
//        case IOT_LOGIN_DEVICE:
//        {
//            this->LoginDevice( con, protoData, datalen, userdata );
//            break;
//        }
//        case IOT_HEART_BEAT:
//        {
//            this->DeviceHeartBeat( con, protoData, datalen, userdata );
//            break;
//        }
//
//
//        case IOT_FIND_GATEWAY:
//        {
//            this->FindGateway( con, protoData, datalen, userdata );
//            break;
//        }
//
//        case IOT_CREATE_DEVICE:
//        {
//            this->CreateDevice( con, protoData, datalen, userdata );
//            break;
//        }
//
//        case IOT_FIND_DEVICE_TOKEN :
//        {
//            this->FindDeviceToken( con, protoData, datalen, userdata );
//            break;
//        }
//
//        case IOT_GENERATE_DEVICE_TOKEN:
//        {
//            this->GenerateDeviceToken( con, protoData, datalen, userdata );
//            break;
//        }
//        default:
//            info( "undefine type IoTBusiness" );
//            break;
//    }
//}

int IoTBusiness::UploadSensor(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{
    IoT::UploadSensorDataAPI uploadSensorDataApi;
    if (!uploadSensorDataApi.ParseFromArray( protoData, datalen ))
    {
        // 失败
        call500( context, "error" );
        return -1;
    }

    if (context->con->context<ServerContext>().getDeviceToken().empty())
    {
        // 失败
        call500( context, "device Not Login" );
        return -1;
    }

    SensorDataType sensorDataType;
    sensorDataType.GatewayId = uploadSensorDataApi.gatewayid();
    sensorDataType.DeviceId = uploadSensorDataApi.deviceid();
    sensorDataType.permission = uploadSensorDataApi.permission();
    sensorDataType.uid = context->con->context<ServerContext>().getUid();
    sensorDataType.key = uploadSensorDataApi.key();
    // 储存的数据
    // TODO 这里 进行 HEX 储存
    sensorDataType.data = StringToHex( uploadSensorDataApi.data());

    DataBaseHelper dataBaseHelper( DATABASENAME );
    int result = dataBaseHelper.getIoTDataBaseFactory()->insertData( sensorDataType );

    if (result == EXIT_SUCCESS)
    {
        std::string outstring = "";
        call200( context, outstring );
    } else
    {
        call500( context, "upload Data Fail " );
    }

    return 0;
}

int IoTBusiness::FindSensor(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{

    IoT::FindSensorDataRequest findSensorDataRequest;
    if (!findSensorDataRequest.ParseFromArray( protoData, datalen ))
    {
        // 失败
        call500( context, "error" );
        return -1;
    }

    uint64_t gatewayid = findSensorDataRequest.gatewayid();
    uint64_t deviceid = findSensorDataRequest.deviceid();

    int64_t currUid = context->con->context<ServerContext>().getUid();

    DataBaseHelper dataBaseHelper( DATABASENAME );

    int ret = dataBaseHelper.getIoTDataBaseFactory()->checkMyDevice( currUid, gatewayid, deviceid );


    std::vector<SensorDataType> datas;

    if (ret == EXIT_SUCCESS)
    {
        // 我的数据
        dataBaseHelper.getIoTDataBaseFactory()->findDataByUid( datas,
                                                               0,
                                                               gatewayid,
                                                               deviceid,
                                                               1,
                                                               findSensorDataRequest.key(),
                                                               findSensorDataRequest.size(),
                                                               findSensorDataRequest.direction(),
                                                               findSensorDataRequest.time()
        );

    } else
    {
        dataBaseHelper.getIoTDataBaseFactory()->findDataByPublic(
                datas,
                findSensorDataRequest.gatewayid(),
                findSensorDataRequest.deviceid(),
                findSensorDataRequest.size(),
                findSensorDataRequest.direction(),
                findSensorDataRequest.time()
        );
    }

    IoT::FindSensorDataRespose findSensorDataRespose;
    findSensorDataRespose.set_gatewayid( gatewayid );
    findSensorDataRequest.set_deviceid( deviceid );
    //

    for (auto data :datas)
    {
        IoT::SensorDataPackage *tempSensorDataPackage = nullptr;
        tempSensorDataPackage = findSensorDataRespose.add_datas();
        tempSensorDataPackage->set_key( data.key );
        tempSensorDataPackage->set_data( HexToString( data.data ));
        tempSensorDataPackage->set_time( data.create );
    }
    std::string outstring;


    if (findSensorDataRespose.SerializeToString( &outstring ))
    {
        call200( context, outstring );
    } else
    {
        call500( context, "error" );
    }
    return 0;
}

int IoTBusiness::ControlDevice(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{
    // 收到 设备控制的操作
    IoT::ControlDeviceRequest controlDeviceRequest;

    if (!controlDeviceRequest.ParseFromArray( protoData, datalen ))
    {
        // 失败
        call500( context, "not found device" );
        return -1;
    }
    //

    std::string serverToken = context->con->context<ServerContext>().getDeviceToken();

    std::string currentTaskCode = genTaskCode();
    std::string currentToken = controlDeviceRequest.token();
    uint64_t currentGatewayId = controlDeviceRequest.gatewayid();
    uint64_t currentDevideId = controlDeviceRequest.deviceid();


    DeviceDataType deviceDataType;
    DataBaseHelper dataBaseHelper( DATABASENAME );
    int64_t serverTime = util::timeMilli();
    int result = dataBaseHelper.getIoTDataBaseFactory()->findDeviceByToken( deviceDataType, currentToken );

    if (result == ERROR_SUCCESS)
    {
        // 查找成功
        info( "IoTBusiness::ControlDevice find success ! " );
        // 存在 这个设备
        // 直接向这个设备 发送请求
        auto findDevice = CacheManager::GetInstance()->deviceTokenMap.find( currentToken );
        if (findDevice != CacheManager::GetInstance()->deviceTokenMap.end())
        {
            IoT::ControlDeviceListerner controlDeviceListerner;

            info( "IoTBusiness::ControlDevice control success " );
            controlDeviceListerner.set_time( serverTime );
            controlDeviceListerner.set_taskcode( currentTaskCode );
            controlDeviceListerner.set_data( controlDeviceRequest.data());
            std::string sendMessage;
            controlDeviceListerner.SerializePartialToString( &sendMessage );
//            mod_currSubType = IOT_CONTROL_LISTERNER;
            call200( NETWORK_MOD_TYPE_IOT, IOT_CONTROL_LISTERNER, 0, findDevice->second, sendMessage );
//            mod_currSubType = IOT_CONTROL_DEVICE;
//            controlDeviceAckListerner

            // 加入 taskmap

            CacheManager::GetInstance()->taskCodeMap[currentTaskCode] = context->con;

        }
    }


    IoT::ControlDeviceRespose controlDeviceRespose;


    controlDeviceRespose.set_taskcode( currentToken );
    controlDeviceRespose.set_time( serverTime );
    std::string outstring;

    if (controlDeviceRespose.SerializePartialToString( &outstring ))
    {
        call200( context, outstring );
        info( " IoTBusiness::ControlDevice : success " );
        return 0;
    } else
    {
        call500( context, " error " );
        return -1;
    }


    return 0;
}

int IoTBusiness::ControlDeviceAck(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{
    IoT::ControlDeviceAckAPI controlDeviceAckApi;

    if (!controlDeviceAckApi.ParseFromArray( protoData, datalen ))
    {
        call500( context, " error " );
        return -1;
    }

    info( "IoTBusiness::ControlDeviceListerner , enter success ... " );
    std::string respTaskcode = controlDeviceAckApi.taskcode();

    auto findDevice = CacheManager::GetInstance()->taskCodeMap.find( respTaskcode );
    if (findDevice != CacheManager::GetInstance()->taskCodeMap.end())
    {
        // 找到
        IoT::ControlDeviceAckListerner controlDeviceAckListerner;
        controlDeviceAckListerner.set_taskcode( respTaskcode );
        controlDeviceAckListerner.set_errcode( controlDeviceAckApi.errcode());
        controlDeviceAckListerner.set_errormsg( controlDeviceAckApi.errormsg());
        controlDeviceAckListerner.set_time( util::timeMilli());

        std::string outString;

        controlDeviceAckListerner.SerializePartialToString( &outString );
//        mod_currSubType = IOT_CONTROL_ACK_LISTERNER;
        call200( NETWORK_MOD_TYPE_IOT, IOT_CONTROL_ACK_LISTERNER, 0, findDevice->second, outString );
//        mod_currSubType = IOT_CONTROL_ACK;
        info( "IoTBusiness::ControlDeviceListerner find success" );
        // 移除队列
        CacheManager::GetInstance()->taskCodeMap.erase( findDevice );
    }

    std::string outString = "";
    call200( context, outString );

    return 0;
}


int IoTBusiness::LoginDevice(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{
    IoT::LoginDeviceAPI loginDeviceApi;

    if (!loginDeviceApi.ParseFromArray( protoData, datalen ))
    {
        // 失败
        call500( context, "error" );
        return -1;
    }

    //
    std::string currentDeviceToken = loginDeviceApi.token();

    std::string serverToken = context->con->context<ServerContext>().getDeviceToken();

    if (serverToken.empty() || serverToken != currentDeviceToken)
    {
        info( "IoTBusiness::LoginDevice %s ", serverToken.c_str());
    }

    DataBaseHelper dataBaseHelper( DATABASENAME );

    int result = dataBaseHelper.getIoTDataBaseFactory()->loginDeviceByToken( currentDeviceToken );

    if (result != ERROR_SUCCESS)
    {
        // 失败
        call500( context, "not found device" );
        return -1;
    }

    // 成功 更新 token

    // 找到 uid
    DeviceDataType deviceDataType;
    dataBaseHelper.getIoTDataBaseFactory()->findDeviceByToken( deviceDataType, currentDeviceToken );


    context->con->context<ServerContext>().setDeviceToken( currentDeviceToken );

    context->con->context<ServerContext>().setUid( deviceDataType.uid );

    std::string outstring = "";

    call200( context, outstring );

//    auto pt = CacheManager::GetInstance()->deviceTokenMap.insert(
//            std::pair<std::string, TcpConnPtr>( currentDeviceToken, con ));

    CacheManager::GetInstance()->deviceTokenMap[currentDeviceToken] = context->con;
//    if (pt.second)
//    {
    info( " IoTBusiness::LoginDevice , add deviceTokenMap success " );
//    } else
//    {
//        info( " IoTBusiness::LoginDevice , add deviceTokenMap fail " );
//    }
    return ERROR_SUCCESS;

}

int IoTBusiness::DeviceHeartBeat(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{

    return 0;
}

int IoTBusiness::FindGateway(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{
    IoT::FindSensorDataRequest findSensorDataRequest;

    if (!findSensorDataRequest.ParseFromArray( protoData, datalen ))
    {
        // 失败
        call500( context, "error" );
        return -1;
    }

    // 解包成功
    int64_t currentUid = context->con->context<ServerContext>().getUid();


    if (currentUid == 0)
    {
        // TODO 没有 登录  则 通过Token 查找当前 uid
    }


    DataBaseHelper dataBaseHelper( DATABASENAME );
    std::vector<uint64_t> outGids;

    dataBaseHelper.getIoTDataBaseFactory()->addOrFindGatewayId( currentUid, outGids );

    IoT::FindGatewayRespose findGatewayRespose;

    findGatewayRespose.set_time( util::timeMilli());
    for (auto gid : outGids)
    {
        findGatewayRespose.add_gatewayid( gid );
    }

    std::string outString;

    if (findGatewayRespose.SerializeToString( &outString ))
    {
        // 成功
        call200( context, outString );
        return ERROR_SUCCESS;
    } else
    {
        call500( context, " error " );
        return ERROR_FAIL;
    }

}

int IoTBusiness::CreateDevice(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{

    IoT::CreateDeviceRequest createDeviceRequest;

    if (!createDeviceRequest.ParseFromArray( protoData, datalen ))
    {
        // 失败
        call500( context, "error" );
        return -1;
    }
    // 解包成功
    int64_t currentUid = context->con->context<ServerContext>().getUid();

    uint64_t currentGatewayid = createDeviceRequest.gatewayid();
    int32_t permission = createDeviceRequest.permission();
//

    std::string note = createDeviceRequest.note();

    uint64_t newDeviceId = 0;
    if (currentUid == 0)
    {
        // TODO 没有 登录  则 通过Token 查找当前 uid
    }

    DataBaseHelper dataBaseHelper( DATABASENAME );
    int ret = -1;
    if (currentUid > 0)
    {
        // 存在
        ret = dataBaseHelper.getIoTDataBaseFactory()->addDevice( currentUid, currentGatewayid, permission, note,
                                                                 newDeviceId );
        info( "IoTBusiness::FindGateway : CreateDevice success " );
    } else
    {
        info( "IoTBusiness::FindGateway : CreateDevice uid not find " );
        //
    }

    if (ret != ERROR_SUCCESS)
    {
        // 失败
        call500( context, "CreateDevice Fail ! " );
        return -1;
    }

    IoT::CreateDeviceRespose createDeviceRespose;

    createDeviceRespose.set_deviceid( newDeviceId );
    createDeviceRespose.set_time( util::timeMilli());

    std::string outString;

    if (createDeviceRespose.SerializeToString( &outString ))
    {
        call200( context, outString );
        return ERROR_SUCCESS;
    } else
    {
        // 失败
        call500( context, "CreateDevice Fail !" );
        return -1;
    }

    return 0;
}

int IoTBusiness::FindDeviceToken(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{
    IoT::FindDeviceTokenRequest findDeviceTokenRequest;

    if (!findDeviceTokenRequest.ParseFromArray( protoData, datalen ))
    {
        // 失败
        call500( context, "error" );
        return -1;
    }

    //
    int64_t currentUid = context->con->context<ServerContext>().getUid();

    if (currentUid == 0)
    {
        // 通过 Token 查找 uid
    }

    uint64_t currentGatewayid = findDeviceTokenRequest.gatewayid();
    uint64_t currentDevideid = findDeviceTokenRequest.deviceid();

    DataBaseHelper dataBaseHelper( DATABASENAME );

    DeviceDataType deviceDataType;
    int ret = dataBaseHelper.getIoTDataBaseFactory()->findDeviceToken( deviceDataType, currentUid, currentGatewayid,
                                                                       currentDevideid );

    info( "IoTBusiness::FindDeviceToken , find ret = %d ", ret );
    if (ret == ERROR_SUCCESS)
    {
        // 成功
        IoT::FindDeviceTokenRespose findDeviceTokenRespose;
        findDeviceTokenRespose.set_time( util::timeMilli());
        findDeviceTokenRespose.set_token( deviceDataType.Token );

        findDeviceTokenRespose.set_gatewayid( deviceDataType.GatewayId );
        findDeviceTokenRespose.set_deviceid( deviceDataType.DevideId );

        std::string outString;

        if (findDeviceTokenRespose.SerializePartialToString( &outString ))
        {
            // 成功
            call200( context, outString );
        } else
        {
            call500( context, "serial error " );
        }
        return ERROR_SUCCESS;
    } else
    {
        // 失败
        call500( context, " unknow Error " );
        return ERROR_FAIL;
    }

}

int IoTBusiness::GenerateDeviceToken(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{
    IoT::GenerateDeviceTokenRequest generateDeviceTokenRequest;

    if (!generateDeviceTokenRequest.ParseFromArray( protoData, datalen ))
    {
        // 失败
        call500( context, "error" );
        return -1;
    }

    //
    int64_t currentUid = context->con->context<ServerContext>().getUid();

    if (currentUid == 0)
    {
        // 通过 Token 查找 uid
    }

    uint64_t currentGatewayid = generateDeviceTokenRequest.gatewayid();
    uint64_t currentDevideid = generateDeviceTokenRequest.deviceid();

    std::string genToken = genNewDeviceToken( currentGatewayid, currentDevideid );

    std::string newToken = GeeJoanMD5( genToken ).toString();

    DataBaseHelper dataBaseHelper( DATABASENAME );
    int ret = dataBaseHelper.getIoTDataBaseFactory()->updataDeviceToken( currentUid, currentGatewayid, currentDevideid,
                                                                         newToken );
    info( "IoTBusiness::GenerateDeviceToken ret = %d ", ret );
    if (ret == ERROR_SUCCESS)
    {
        IoT::GenerateDeviceTokenRespose generateDeviceTokenRespose;
        generateDeviceTokenRespose.set_token( newToken );
        generateDeviceTokenRespose.set_time( util::timeMilli());

        std::string outString;

        if (generateDeviceTokenRequest.SerializePartialToString( &outString ))
        {
            // 序列化成
            call200( context, outString );
            return ERROR_SUCCESS;

        } else
        {
            call500( context, " GenerateDeviceToken serial fail " );
            return ERROR_FAIL;
        }
    } else
    {
        call500( context, " GenerateDeviceToken fail " );
        return ERROR_FAIL;
    }


}


int IoTBusiness::FindMyDevices(EventContext *context, uint8_t *protoData, int datalen, void *userdata)
{
    return 0;
}

int IoTBusiness::dispatchEvents(
        int type_sub,
        int taskid,
        const TcpConnPtr &con,
        uint8_t *protoData,
        int datalen,
        void *userdata)
{
    auto findEvent = this->eventMap.find( type_sub );

    int ret = ERROR_FAIL;
    if (findEvent != this->eventMap.end())
    {
        EventContext eventContext {
                .mod_type = NETWORK_MOD_TYPE_IOT,
                .sub_type = type_sub,
                .taskid = taskid,
                .con = con
        };
        ret = findEvent->second( &eventContext, protoData, datalen, userdata );
    } else
    {
        info( "IoTBusiness::dispatchEvents , not found event , type = %d ", type_sub );
    }


    return ret;
}

void IoTBusiness::setEvents()
{
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_UPLOAD_SENSOR_DATA, this->UploadSensor ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_FIND_SENSOR_DATA, this->FindSensor ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_CONTROL_DEVICE, this->ControlDevice ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_CONTROL_ACK, this->ControlDeviceAck ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_LOGIN_DEVICE, this->LoginDevice ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_HEART_BEAT, this->DeviceHeartBeat ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_FIND_GATEWAY, this->FindGateway ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_CREATE_DEVICE, this->CreateDevice ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_FIND_DEVICE_TOKEN, this->FindDeviceToken ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_GENERATE_DEVICE_TOKEN, this->GenerateDeviceToken ));
    this->eventMap.insert( std::pair<int, EventFunction>( IOT_FIND_MY_DEVICE, this->FindMyDevices ));
}

IoTBusiness::IoTBusiness()
{
    info( "init IoTBusiness " );
}

IoTBusiness::~IoTBusiness()
{
    info( "delete IoTBusiness " );
}
